package cn.lg.soar.redis.manager;

import cn.lg.soar.core.manager.SoarLock;
import cn.lg.soar.core.manager.SoarLockManager;
import jakarta.annotation.Resource;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

public class RedisSoarLockManager implements SoarLockManager {

    Logger logger = LoggerFactory.getLogger(RedisSoarLockManager.class);

    @Resource
    private Redisson redisson;

    @Override
    public SoarLock getLock(String lockName) {
        RLock lock = redisson.getLock(lockName);
        return new RedisSoarLock(lock);
    }

    @Override
    public SoarLock getFairLock(String lockName) {
        RLock lock = redisson.getFairLock(lockName);
        return new RedisSoarLock(lock);
    }

    @Override
    public <T> T lock(String lockName, long waitTime, long leaseTime, Supplier<T> handler) {
        RLock lock = this.redisson.getLock(lockName);
        try {
            if (lock.tryLock(waitTime, leaseTime, TimeUnit.MILLISECONDS)) {
                return handler.get();
            } else {
                logger.info("无法获取锁：{}", lockName);
                throw new RuntimeException("他人正在操作，请稍后重试！");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢复中断状态
            throw new RuntimeException("线程被中断", e);
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    @Override
    public <T> T lock(String lockName, long waitTime, Supplier<T> handler) {
        RLock lock = this.redisson.getLock(lockName);
        try {
            if (lock.tryLock(waitTime, -1, TimeUnit.MILLISECONDS)) {
                return handler.get();
            } else {
                logger.info("无法获取锁：{}", lockName);
                throw new RuntimeException("他人正在操作，请稍后重试！");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢复中断状态
            throw new RuntimeException("线程被中断", e);
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    @Override
    public void lock(String lockName, long waitTime, long leaseTime, Runnable handler) {
        RLock lock = this.redisson.getLock(lockName);
        try {
            if (lock.tryLock(waitTime, leaseTime, TimeUnit.MILLISECONDS)) {
                handler.run();
            } else {
                logger.info("无法获取锁：{}", lockName);
                throw new RuntimeException("他人正在操作，请稍后重试！");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢复中断状态
            throw new RuntimeException("线程被中断", e);
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    @Override
    public void lock(String lockName, long waitTime, Runnable handler) {
        RLock lock = this.redisson.getLock(lockName);
        try {
            if (lock.tryLock(waitTime, -1, TimeUnit.MILLISECONDS)) {
                handler.run();
            } else {
                logger.info("无法获取锁：{}", lockName);
                throw new RuntimeException("他人正在操作，请稍后重试！");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢复中断状态
            throw new RuntimeException("线程被中断", e);
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}
